package com.ddwl.goods.service;

import cn.hutool.core.util.StrUtil;
import com.ddwl.common.constant.GoodsEnum;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.feign.api.UserApi;
import com.ddwl.common.feign.api.WalletApi;
import com.ddwl.common.util.UUIDGenerator;
import com.ddwl.goods.dao.SignInDao;
import com.ddwl.goods.model.SignIn;
import com.ddwl.schema.bo.goods.SignHistBo;
import com.ddwl.schema.bo.wallet.ProvideSubsidyBo;
import com.ddwl.schema.util.DateUtil;
import com.ddwl.schema.vo.base.RestVo;
import com.ddwl.schema.vo.goods.SignConfigVo;
import com.ddwl.schema.vo.goods.SignHistVo;
import com.ddwl.schema.vo.goods.SignInVo;
import com.ddwl.schema.vo.user.UserVo;
import io.gitee.tooleek.lock.spring.boot.annotation.Key;
import io.gitee.tooleek.lock.spring.boot.annotation.Lock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Instant;
import java.util.Optional;

/**
 * @Author hemiaojun
 * @Date 2020/10/20 15:37
 */
@Service
public class SignInService {

    @Resource
    private SignInDao signInDao;
    @Resource
    private SignHistService signHistService;
    @Resource
    private SignConfigService signConfigService;
    @Resource
    private UserApi userApi;
    @Resource
    private WalletApi walletApi;

    @Lock
    @Transactional(rollbackFor = Exception.class)
    public SignInVo signIn(@Key String userId) {
        return doSignIn(userId, Instant.now(), Boolean.FALSE);
    }

    private SignInVo doSignIn(String userId, Instant date, boolean reissue) {
        ParamException.isTrue(StrUtil.isEmpty(userId), "未获取到用户信息");
        SignIn signIn = getByUserId(userId);
        String dayOfWeek = DateUtil.getDayOfWeek(date);
        Integer weekCode = GoodsEnum.WeekEnum.getCodeBYDay(dayOfWeek);
        SignInVo signInVo = new SignInVo();
        if (null == signIn) {
            SignIn entity = initSignIn(userId, dayOfWeek);
            signInDao.insert(entity);
        } else {
            SignHistVo signHistVo = signHistService.getByUserIdAndSignDate(userId, DateUtil.formatDate(date, DateUtil.DATE_FORMAT));
            if (null != signHistVo) {
                signInVo.setSignDays(signIn.getSignDays());
                signInVo.setSignStatus(2);
                signInVo.setSignReward(signHistVo.getSignReward());
                return signInVo;
            }
            if (Optional.ofNullable(signIn.getGmtModified()).orElse(signIn.getGmtCreated()).isBefore(DateUtil.getMondayOfWeek(date))) {
                SignIn entity = initSignIn(userId, dayOfWeek);
                entity.setId(signIn.getId());
                signInDao.updateByPrimaryKeySelective(entity);
            } else {
                if (!reissue) {
                    signIn.setWeekCode(weekCode);
                }
                signIn.setSignDays(signIn.getSignDays() + 1);
                signInDao.updateByPrimaryKeySelective(signIn);
            }
        }
        SignHistBo shBo = addSignHist(userId, dayOfWeek, date, reissue);
        signSubsidy(shBo);

        signInVo.setSignDays(shBo.getSignDays());
        signInVo.setSignStatus(1);
        signInVo.setSignReward(shBo.getSignReward());
        return signInVo;
    }

    private SignHistBo addSignHist(String userId, String dayOfWeek, Instant signDate, boolean reissue) {
        SignIn signInNew = getByUserId(userId);
        RestVo<UserVo> restVo = userApi.getProfile(userId);
        UserVo userVo = restVo.getResult();
        ParamException.isNull(userVo, "未获取到用户信息");
        SignConfigVo signConfigVo = signConfigService.getByDay(dayOfWeek);
        SignConfigVo sunConfig = signConfigService.getByDay(GoodsEnum.WeekEnum.SUN.getDayOfWeek());
        SignHistBo signHistBo = new SignHistBo();
        signHistBo.setId(UUIDGenerator.getShortUUID());
        signHistBo.setUserId(userId);
        signHistBo.setUserName(userVo.getNickname());
        signHistBo.setMobile(userVo.getMobile());
        signHistBo.setContinueDays(signInNew.getContinueDays());
        signHistBo.setSignDays(signInNew.getSignDays());
        if (reissue) {
            signHistBo.setReissue(GoodsEnum.SignEnum.REISSUE.getCode());
        } else {
            signHistBo.setReissue(GoodsEnum.SignEnum.NOT_REISSUE.getCode());
        }
        signHistBo.setSignId(signInNew.getId());
        signHistBo.setSignDate(signDate);
        signHistBo.setDayOfWeek(dayOfWeek);
        if (null != signConfigVo) {
            signHistBo.setRewardType(signConfigVo.getRewardType());
            if (signInNew.getSignDays().equals(GoodsEnum.WeekEnum.SUN.getCode())) {
                signHistBo.setSignReward(sunConfig.getContinueReward());
            } else {
                if (reissue) {
                    signHistBo.setSignReward(signConfigVo.getReissueReward());
                } else {
                    signHistBo.setSignReward(signConfigVo.getRewardNum());
                }
            }
        }
        signHistService.add(signHistBo);
        return signHistBo;
    }

    private void signSubsidy(SignHistBo bo) {
        ProvideSubsidyBo provideSubsidyBo = new ProvideSubsidyBo();
        provideSubsidyBo.setUserId(bo.getUserId());
        provideSubsidyBo.setFlowId(bo.getId());
        provideSubsidyBo.setMsg("签到送津贴");
        provideSubsidyBo.setType(1);
        provideSubsidyBo.setRewardSubsidy(bo.getSignReward());
        walletApi.provideSubsidy(provideSubsidyBo);
    }

    private SignIn initSignIn(String userId, String dayOfWeek) {
        SignIn signIn = new SignIn();
        signIn.setUserId(userId);
        signIn.setWeekCode(GoodsEnum.WeekEnum.getCodeBYDay(dayOfWeek));
        signIn.setSignDays(GoodsEnum.SignEnum.ONE.getCode());
        signIn.setContinueDays(GoodsEnum.SignEnum.ONE.getCode());
        return signIn;
    }

    private SignIn getByUserId(String userId) {
        SignIn signIn = new SignIn();
        signIn.setUserId(userId);
        return signInDao.selectOne(signIn);
    }

    @Transactional(rollbackFor = Exception.class)
    public SignInVo reissue(String userId, Instant signDate) {
        ParamException.isTrue(signDate.compareTo(Instant.now()) > 0, "只能补签今天之前的日期");
        return doSignIn(userId, signDate, Boolean.TRUE);
    }
}
